package com.sls.game.service.impl;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.sls.core.common.CommonUtil;
import com.sls.core.http.HttpClient;
import com.sls.core.socket.Head;
import com.sls.core.socket.ServerDisponseException;
import com.sls.core.util.PropertiesUtil;
import com.sls.core.util.ServerDateAndTime;
import com.sls.core.util.UtilMD5Encryption;
import com.sls.game.common.DeductionRefund;
import com.sls.game.constant.ExceptionCodeDes;
import com.sls.game.dao.DownstreamUserDAO;
import com.sls.game.dao.GoodsOrderDAO;
import com.sls.game.dao.xinhe.XinHeAccountDAO;
import com.sls.game.dao.xinhe.XinHeChargeUnitDAO;
import com.sls.game.dao.xinhe.XinHeCompanyDAO;
import com.sls.game.dao.xinhe.XinHeGameDAO;
import com.sls.game.dao.xinhe.XinHeGameGiftDAO;
import com.sls.game.dao.xinhe.XinHeProductDAO;
import com.sls.game.page.Pagination;
import com.sls.game.parser.ParseXinHeXml;
import com.sls.game.parser.sls.OrderStatusSendParse;
import com.sls.game.pojo.DeductionRefundInfo;
import com.sls.game.pojo.DownstreamUserInfo;
import com.sls.game.pojo.GoodsOrderInfo;
import com.sls.game.pojo.SLSHttpInterfaceInfo;
import com.sls.game.pojo.xinhe.Company;
import com.sls.game.pojo.xinhe.XinHeProduct;
import com.sls.game.pojo.xinhe.XinHeRespInfo;
import com.sls.game.service.XinHeService;

@Service("xinHeService")
public class XinHeServiceImpl implements XinHeService {

	private static Logger log = Logger.getLogger(XinHeServiceImpl.class);
	private static String fileName = "xinhe.properties";
	@Resource(name = "xinHeProductDAO")
	private XinHeProductDAO productDao;
	@Resource(name = "xinHeAccountDAO")
	private XinHeAccountDAO accountDao;
	@Resource(name = "xinHeGameDAO")
	private XinHeGameDAO gameDao;
	@Resource(name = "xinHeChargeUnitDAO")
	private XinHeChargeUnitDAO chargeDao;
	@Resource(name = "xinHeGameGiftDAO")
	private XinHeGameGiftDAO giftDao;
	@Resource(name = "xinHeCompanyDAO")
	private XinHeCompanyDAO comDao;
	@Resource(name = "goodsOrderDAO")
	private GoodsOrderDAO goodsOrderDAO;
	@Resource(name = "downstreamUserDAO")
	private DownstreamUserDAO downstreamUserDAO;

	private Gson gson;

	public XinHeServiceImpl() {
		gson = CommonUtil.gson();
	}
	
	@Override
	public Pagination<XinHeProduct> queryXHProPagination(String body, Head head) {
		XinHeProduct product = gson.fromJson(body, XinHeProduct.class);
		Pagination<XinHeProduct> page = this.productDao.queryPage(product);
		return page;
	}

	@Override
	public XinHeProduct queryXHProductById(String body, Head head) {
		XinHeProduct pro = gson.fromJson(body, XinHeProduct.class);
		String id = pro.getId();
		XinHeProduct product = this.productDao.queryById(id);
		return product;
	}
	
	@Override
	public void update(String body, Head head) {
		XinHeProduct pro = gson.fromJson(body, XinHeProduct.class);
		pro.setModifyTime(ServerDateAndTime.getNowDateTimeOfFormat());
		this.productDao.update(pro);
	}


	
	@Override
	public void updateTemplateInfo(String body, Head head) {
		XinHeRespInfo rs = gson.fromJson(body, XinHeRespInfo.class);
		String companyId = rs.getCompanyId();
		String address = PropertiesUtil.getValue(
				"xinhe.recharge.template.address", fileName);
		String userId = rs.getUserId();
		HttpClient hc = new HttpClient();
		Map<String, String> map = new HashMap<String, String>();
		map.put("companyId", companyId);
		map.put("userId", userId);
		try {
			log.info("请求ID：" + head.getRequestId() + "，访问鑫合充值模板请求地址："
					+ address +map);
			String xml = hc.doPost(address, map);
			log.info("请求ID：" + head.getRequestId() + "，鑫合充值模板请求返回："
					+ xml);
			ParseXinHeXml.insertProductInfo(xml, companyId, productDao,
					accountDao, gameDao, chargeDao, giftDao);
		} catch (Exception e) {
			log.info("请求ID：" + head.getRequestId() + "，访问鑫合充值模板出现异常", e);
		}
	}


	@Override
	public void saveSyncInfo(Head head) {
		final List<Company> list = this.getCompanyList(head);
		final Head head2 = head;
		new Thread(new Runnable(){

			@Override
			public void run() {
				
				String address = PropertiesUtil.getValue(
						"xinhe.recharge.template.address", fileName);
				String userId = PropertiesUtil.getValue("xinhe.merchant.id", fileName);
				HttpClient hc = new HttpClient();
				Map<String, String> map = new HashMap<String, String>();
				if (list != null && !list.isEmpty()) {
					for (Company com : list) {
						String companyId = com.getId();
						map.put("companyId", companyId);
						map.put("userId", userId);
						try {
							log.info("请求ID：" + head2.getRequestId() + "，访问鑫合充值模板请求地址："
									+ address + map);
							String xml = hc.doPost(address, map);
							log.info("请求ID：" + head2.getRequestId() + "，鑫合充值模板请求返回："
									+ xml);
							ParseXinHeXml.insertProductInfo(xml, companyId, productDao,
									accountDao, gameDao, chargeDao, giftDao);
						} catch (Exception e) {
							log.info("请求ID：" + head2.getRequestId() + "，访问鑫合充值模板出现异常", e);
						}
					}
				}
				
			}
			
		}).start();
		
	}

	private List<Company> getCompanyList(Head head) {
		String address = PropertiesUtil.getValue(
				"xinhe.game.company.list.address", fileName);
		HttpClient hc = new HttpClient();
		Map<String, String> map = new HashMap<String, String>();
		List<Company> list = new ArrayList<Company>();
		try {
			log.info("请求ID：" + head.getRequestId() + "，访问鑫合游戏厂商列表请求地址："
					+ address);
			String xml = hc.doPost(address, map);
			log.info("请求ID：" + head.getRequestId() + "，鑫合游戏厂商列表返回：" + xml);
			list = ParseXinHeXml.getAllCompanys(xml, comDao);
		} catch (Exception e) {
			log.info("请求ID：" + head.getRequestId() + "，访问鑫合游戏厂商列表出现异常", e);
		}
		return list;
	}
	

	@Override
	public XinHeRespInfo queryOrder(String body, Head head) {
		XinHeRespInfo reqInfo = gson.fromJson(body, XinHeRespInfo.class);
		if (reqInfo == null) {
			throw new ServerDisponseException(
					ExceptionCodeDes.PARSE_REQUEST_ERROR.getCode(),
					ExceptionCodeDes.PARSE_REQUEST_ERROR.getDescription());
		}
		String orderId = reqInfo.getOrderNo();
		if (StringUtils.isEmpty(orderId)) {
			throw new ServerDisponseException(
					ExceptionCodeDes.SLS_ORDERNO_NULL.getCode(),
					ExceptionCodeDes.SLS_ORDERNO_NULL.getDescription());
		}

		XinHeRespInfo respInfo = null;
		String address = PropertiesUtil.getValue(
				"xinhe.order.query.address", fileName);
		String md5key = PropertiesUtil.getValue("xinhe.md5.key", fileName);
		String merchantId = PropertiesUtil.getValue("xinhe.merchant.id",
				fileName);
		HttpClient httpClient = new HttpClient();
		String data = orderId+merchantId + md5key;
		String sign = UtilMD5Encryption.createMD5Encryption(data);
		Map<String, String> pMap = new HashMap<String, String>();
		pMap.put("userId", merchantId);
		pMap.put("orderNo", orderId);
		pMap.put("sign", sign);
		try {
			log.info("请求ID：" + head.getRequestId() + "--发送到鑫合订单查询的请求参数："
					+ address + pMap);
			String returnMsg = httpClient.doPost(address, pMap);
			log.info("请求ID：" + head.getRequestId() + "--鑫合返回给的请求结果："
					+ returnMsg);
			if (StringUtils.isNotEmpty(returnMsg)) {
				respInfo = ParseXinHeXml.getReturnOfXinHe(returnMsg);
				String msg = map.get(respInfo.getReturnMsg());
				respInfo.setReturnMsg(msg);
			}
		} catch (Exception e) {
			log.error("请求ID：" + head.getRequestId() + "--鑫合订单查询请求异常！", e);
		}
		return respInfo;

	}

	@Override
	public void updateOrderStatus(String body, Head head) {
		log.info("请求ID：" + head.getRequestId() + "，鑫合异步通知参数：" + body);
		XinHeRespInfo asyncInfo = gson.fromJson(body, XinHeRespInfo.class);
		// 成功处理时间
		String orderSuccessTime = ServerDateAndTime.getNowDateTime().trim();
		String orderSuccessTime2 = ServerDateAndTime.getNowDateTimeOfFormat().trim();
		boolean flag = this.checkData(asyncInfo, head);
		if (flag) {
			// 主动通知下游用户
			String userhandleResult = sendNotifyToDownUserMsg(asyncInfo,
					orderSuccessTime, head);
			updateGoodsOrder(head, asyncInfo, orderSuccessTime2,
					userhandleResult);
		}
	}

	private boolean checkData(XinHeRespInfo asyncInfo, Head head) {
		boolean flag = false;
		if (StringUtils.isEmpty(asyncInfo.getOrderNo())) {
			log.info("请求ID：" + head.getRequestId() + "，经销商流水号为空");
			throw new ServerDisponseException("ORDER_NO_EMPTY", "经销商流水号为空");
		} else if (StringUtils.isEmpty(asyncInfo.getXhOrder())) {
			log.info("请求ID：" + head.getRequestId() + "，鑫合流水号为空");
			throw new ServerDisponseException("XINHE_ORDER_EMPTY", "鑫合流水号为空");
		} else if (StringUtils.isEmpty(asyncInfo.getResult())) {
			log.info("请求ID：" + head.getRequestId() + "，订单状态为空");
			throw new ServerDisponseException("OEDER_STATUS_EMPTY", "订单状态为空");
		} else {
			flag = true;
		}
		return flag;

	}

	private void updateGoodsOrder(Head head, XinHeRespInfo asyncInfo,
			String orderSuccessTime, String userhandleResult) {
		// 订单编号
		String orderNo = asyncInfo.getOrderNo();
		// SUP平台订单号
		String supOrderNo = asyncInfo.getXhOrder();
		// 订单交易状态
		String statusCode = asyncInfo.getResult();
		String snapshot = asyncInfo.getSnapshot();

		GoodsOrderInfo goodsOrderInfo = new GoodsOrderInfo();
		goodsOrderInfo.setOrderId(orderNo);
		goodsOrderInfo.setSupOrderId(supOrderNo);

		String status = "1";
		if ("000".equals(statusCode)) { // 成功
			status = "1";
		} else { // 失败
			status = "0";
			// 退款操作
			DeductionRefundInfo dedInfo = null;
			dedInfo = DeductionRefund.refundWhenAsynCallBackFailed(orderNo,
					goodsOrderDAO, head);
			String paymentStatus = "";
			if (dedInfo != null) {
				paymentStatus = dedInfo.getPaymentStatus();
			}
			if ("1".equals(paymentStatus)) { // 成功
				goodsOrderInfo.setIsPay("3"); // 退款成功
				// 退款成功，通知下游用户
				DeductionRefund.noticeUserRefundMsg(orderNo, dedInfo,
						goodsOrderDAO, downstreamUserDAO, null);

			} else if ("2".equals(paymentStatus)) {
				GoodsOrderInfo orderInfo = goodsOrderDAO
						.queryByOrderId(orderNo);
				if (orderInfo != null) {
					String isPayValue = orderInfo.getIsPay(); // 支付状态值
					if ("1".equals(isPayValue)) {
						goodsOrderInfo.setIsPay("2"); // 退款失败
					}
				}
			}
		}
		goodsOrderInfo.setStatus(status);
		goodsOrderInfo.setStatusRemark(snapshot);
		if("000".equals(statusCode)){
			goodsOrderInfo.setSupOrderSuccessTime(orderSuccessTime);
		}
		goodsOrderInfo.setUserhandleResult(userhandleResult);
		goodsOrderInfo.setSynOrAsy("1"); // 异步推送
		// 数据更新
		try {
			goodsOrderDAO.update(goodsOrderInfo);
		} catch (Exception e) {
			log.error("鑫合异步推送更新订单异常", e);
			throw new ServerDisponseException(
					ExceptionCodeDes.ACCESS_DATABASE_ERROR.getCode(),
					ExceptionCodeDes.ACCESS_DATABASE_ERROR.getDescription());
		}

	}

	private String sendNotifyToDownUserMsg(XinHeRespInfo asyncInfo,
			String orderSuccessTime, Head head) {
		String handleResult = "FAILED";
		String orderId = asyncInfo.getOrderNo();
		GoodsOrderInfo orderInfo = this.goodsOrderDAO.queryByOrderId(orderId);
		String notifyUrl = "";
		// 下游用户编号
		String contractId = null;
		if (orderInfo != null) {
			notifyUrl = orderInfo.getNotifyUrl();
			contractId = orderInfo.getContractId();

			String secretKey = null; // 下游用户密钥
			DownstreamUserInfo downstreamUserInfo = downstreamUserDAO
					.queryUserByUserNO(contractId);
			if (downstreamUserInfo != null) {
				secretKey = downstreamUserInfo.getSecretKey();
			}
			String httpUrl = notifyUrl
					+ "?"
					+ this.assembleParameter(asyncInfo, orderInfo, secretKey,
							orderSuccessTime);

			HttpClient httpClient = new HttpClient();
			// 供应商返回消息编码方式
			String supplyEncode = "UTF-8";
			// 给下游发消息
			String xmlStr = "";
			try {
				log.info("请求ID：" + head.getRequestId() + "，祥钻异步回调给下游用户的url："
						+ httpUrl);
				xmlStr = httpClient.doGet(httpUrl, supplyEncode);
				log.info("请求ID：" + head.getRequestId() + "，下游用户的返回结果：" + xmlStr);
			} catch (Exception e) {
				log.error("请求ID：" + head.getRequestId() + "，主动通知下游用户出现异常！", e);
			}
			if (StringUtils.isNotBlank(xmlStr)) {
				SLSHttpInterfaceInfo slsInfo = null;
				slsInfo = OrderStatusSendParse.readUserSendMsg(xmlStr);
				if (slsInfo != null) {
					handleResult = slsInfo.getHandleResult();
				}
			}
		}
		return handleResult;
	}

	private String assembleParameter(XinHeRespInfo asyncInfo,
			GoodsOrderInfo orderInfo, String secretKey, String orderSuccessTime) {
		// 下游用户订单号
		String ptOrderNo = orderInfo.getMerchantOrderId();
		// 订单号
		String supOrderNo = asyncInfo.getOrderNo();
		// 充值后状态
		String orderState = asyncInfo.getResult();
		String err_msg = map.get(orderState);

		StringBuilder strBui = new StringBuilder();
		strBui.append("ptOrderNo=");
		strBui.append(ptOrderNo);
		strBui.append("&");
		strBui.append("supOrderNo=");
		strBui.append(supOrderNo);
		strBui.append("&");
		strBui.append("status=");
		String status = null;
		if ("000".equals(orderState)) { // 成功
			status = "ORDER_SUCCESS";
			err_msg = ""; // 成功了为空
		} else { // 失败
			status = "ORDER_FAILED"; // 失败
		}
		strBui.append(status);
		strBui.append("&");

		if ("ORDER_SUCCESS".equals(status)) { // 订单成功，才传成功充值时间
			strBui.append("supOrderSuccessTime=");
			strBui.append(orderSuccessTime);
			strBui.append("&");
		} else { // 订单失败时，才传错误原因
			strBui.append("failedReason=");
			String fr = "";
			if (StringUtils.isNotBlank(err_msg)) {
				try {
					fr = URLEncoder.encode(err_msg, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					log.error("编码异常", e);
				}
			}
			strBui.append(fr);
			strBui.append("&");
		}

		strBui.append("sign=");
		String sign = createSign(ptOrderNo, supOrderNo, status,
				orderSuccessTime, err_msg, secretKey);
		strBui.append(sign);
		log.info("异步发送给下游用户的订单处理结果    \n 合作方订单编号:" + ptOrderNo + "\n 祥钻订单编号:"
				+ supOrderNo + "\n 订单最终处理结果：" + status + "\n订单处理的时间:"
				+ orderSuccessTime + "\n失败原因：" + err_msg);

		String result = strBui.toString().trim();
		return result;
	}

	private String createSign(String ptOrderNo, String supOrderNo,
			String status, String orderSuccessTime, String err_msg,
			String secretKey) {
		StringBuilder strBui = new StringBuilder();
		strBui.append(ptOrderNo);
		strBui.append(supOrderNo);
		strBui.append(status);
		if (StringUtils.isNotBlank(orderSuccessTime)) {
			strBui.append(orderSuccessTime);
		}
		if (StringUtils.isNotBlank(err_msg)) {
			strBui.append(err_msg);
		}
		strBui.append(secretKey);
		String data = strBui.toString().trim();
		String result = UtilMD5Encryption.createMD5Encryption(data);
		return result;
	}

	private static Map<String, String> map = new HashMap<String, String>();

	static {
		map.put("000", "成功");
		map.put("010", "充值中,表示已接受充值请求,将异步返回充值结果");
		map.put("001", "失败");
		map.put("002", "游戏区不存在");
		map.put("003", "游戏服务器不存在");
		map.put("006", "充值产品类型不存在");
		map.put("007", "游戏类型不存在");
		map.put("008", "游戏卡密错误");
		map.put("009", "流水号不存在");
		map.put("011", "IP错误");
		map.put("012", "库存不足");
		map.put("013", "玩家帐号不存在");
		map.put("014", "玩家帐号状态异常");
		map.put("015", "角色不存在");
		map.put("016", "角色信息异常");
		map.put("017", "经销商储值帐号不存在");
		map.put("018", "经销储值帐号被禁用");
		map.put("019", "经销商储值帐号余额不足");
		map.put("020", "游戏厂商异常");
		map.put("021", "游戏厂商关闭");
		map.put("100", "重复提交");
		map.put("403", "请求超时");
		map.put("500", "未知错误");
		map.put("501", "参数错误");
		map.put("502", "数字签名错误");
		map.put("555", "此功能暂时不可用，系统维护中");
	}



}
